/* ------------------------------------------
 * Copyright (c) 2017, Synopsys, Inc. All rights reserved.

 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:

 * 1) Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.

 * 2) Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.

 * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may
 * be used to endorse or promote products derived from this software without
 * specific prior written permission.

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
   --------------------------------------------- */

#ifndef _DW_IIC_H_
#define _DW_IIC_H_

#include "device/ip_hal/dev_iic.h"
#include "arc/arc_exception.h"

/**
 * If this header file is included,
 * will indicate that this designware iic device
 * is used
 */
#define DEVICE_USE_DESIGNWARE_IIC

#define DW_IIC_MASTER_SUPPORTED         (0x1)   /*!< Support Designware IIC Master Mode */
#define DW_IIC_SLAVE_SUPPORTED          (0x2)   /*!< Support Designware IIC Slave Mode */
/*!< Support Designware IIC Both Master and Slave Mode */
#define DW_IIC_BOTH_SUPPORTED           (DW_IIC_MASTER_SUPPORTED | DW_IIC_SLAVE_SUPPORTED)

#define DW_IIC_INVALID_INTNO            (DEV_INTNO_INVALID)

enum {
	DW_IIC_CAP_LOADING_100PF = 0,
	DW_IIC_CAP_LOADING_400PF
};

/**
 * @defgroup	DEVICE_DW_IIC_REGSTRUCT		DesignWare IIC Register Structure
 * @ingroup	DEVICE_DW_I2S
 * @brief	Structure definitions for DesignWare IIC register
 * @details	Detailed struct description of DesignWare IIC
 *	block register information, implementation of DEV_IIC_INFO::iic_regs
 * @{
 */
typedef volatile struct dw_iic_reg {
	uint32_t IC_CON;                /*!< (0x00) : IIC control */
	uint32_t IC_TAR;                /*!< (0x04) : IIC target address */
	uint32_t IC_SAR;                /*!< (0x08) : IIC slave address */
	uint32_t IC_HS_MADDR;           /*!< (0x0c) : IIC HS Master Mode Code address */
	uint32_t IC_DATA_CMD;           /*!< (0x10) : IIC Rx/Tx Data Buffer and Command */
	uint32_t IC_SS_SCL_HCNT;        /*!< (0x14) : Standard Speed IIC clock SCL High Count */
	uint32_t IC_SS_SCL_LCNT;        /*!< (0x18) : Standard Speed IIC clock SCL Low Count */
	uint32_t IC_FS_SCL_HCNT;        /*!< (0x1c) : Fast Speed IIC clock SCL Low Count */
	uint32_t IC_FS_SCL_LCNT;        /*!< (0x20) : Fast Speed IIC clock SCL Low Count */
	uint32_t IC_HS_SCL_HCNT;        /*!< (0x24) : High Speed IIC clock SCL Low Count */
	uint32_t IC_HS_SCL_LCNT;        /*!< (0x28) : High Speed IIC clock SCL Low Count */
	uint32_t IC_INTR_STAT;          /*!< (0x2c) : IIC Interrupt Status */
	uint32_t IC_INTR_MASK;          /*!< (0x30) : IIC Interrupt Mask */
	uint32_t IC_RAW_INTR_STAT;      /*!< (0x34) : IIC Raw Interrupt Status */
	uint32_t IC_RX_TL;              /*!< (0x38) : IIC Receive FIFO Threshold */
	uint32_t IC_TX_TL;              /*!< (0x3c) : IIC Transmit FIFO Threshold */
	uint32_t IC_CLR_INTR;           /*!< (0x40) : Clear combined and Individual Interrupts */
	uint32_t IC_CLR_RX_UNDER;       /*!< (0x44) : Clear RX_UNDER Interrupt */
	uint32_t IC_CLR_RX_OVER;        /*!< (0x48) : Clear RX_OVER Interrupt */
	uint32_t IC_CLR_TX_OVER;        /*!< (0x4c) : Clear TX_OVER Interrupt */
	uint32_t IC_CLR_RD_REQ;         /*!< (0x50) : Clear RQ_REQ Interrupt */
	uint32_t IC_CLR_TX_ABRT;        /*!< (0x54) : Clear TX_ABRT Interrupt */
	uint32_t IC_CLR_RX_DONE;        /*!< (0x58) : Clear RX_DONE Interrupt */
	uint32_t IC_CLR_ACTIVITY;       /*!< (0x5c) : Clear ACTIVITY Interrupt */
	uint32_t IC_CLR_STOP_DET;       /*!< (0x60) : Clear STOP_DET Interrupt */
	uint32_t IC_CLR_START_DET;      /*!< (0x64) : Clear START_DET Interrupt */
	uint32_t IC_CLR_GEN_CALL;       /*!< (0x68) : Clear GEN_CALL Interrupt */
	uint32_t IC_ENABLE;             /*!< (0x6c) : IIC Enable */
	uint32_t IC_STATUS;             /*!< (0x70) : IIC Status */
	uint32_t IC_TXFLR;              /*!< (0x74) : Transmit FIFO Level Register */
	uint32_t IC_RXFLR;              /*!< (0x78) : Receive FIFO Level Register */
	uint32_t IC_SDA_HOLD;           /*!< (0x7c) : SDA Hold Time Length Reg */
	uint32_t IC_TX_ABRT_SOURCE;     /*!< (0x80) : IIC Transmit Abort Status Reg */
	uint32_t IC_SLV_DATA_NACK_ONLY; /*!< (0x84) : Generate SLV_DATA_NACK Register */
	uint32_t IC_DMA_CR;             /*!< (0x88) : DMA Control Register */
	uint32_t IC_DMA_TDLR;           /*!< (0x8c) : DMA Transmit Data Level */
	uint32_t IC_DMA_RDLR;           /*!< (0x90) : DMA Receive Data Level */
	uint32_t IC_SDA_SETUP;          /*!< (0x94) : SDA Setup Register */
	uint32_t IC_ACK_GENERAL_CALL;   /*!< (0x98) : ACK General Call Register */
	uint32_t IC_ENABLE_STATUS;      /*!< (0x9c) : Enable Status Register */
	uint32_t IC_FS_SPKLEN;          /*!< (0xa0) : ISS and FS spike suppression limit */
	uint32_t IC_HS_SPKLEN;          /*!< (0xa4) : HS spike suppression limit */
	uint32_t RESERVED[19];          /*!< (0xa8) : Reserved */
	uint32_t IC_COMP_PARAM_1;       /*!< (0xf4) : Component Parameter Register */
	uint32_t IC_COMP_VERSION;       /*!< (0xf8) : Component Version ID Reg */
	uint32_t IC_COMP_TYPE;          /*!< (0xfc) : Component Type Reg */
} DW_IIC_REG, *DW_IIC_REG_PTR;
/** @} */

/** Spike Suppression Limit Configurations */
typedef struct dw_iic_spklen {
	uint32_t fs_spklen;     /*!< value for IC_FS_SPKLEN, Tsp for fast mode is 50ns */
	uint32_t hs_spklen;     /*!< value for IC_HS_SPKLEN, Tsp for high-speed mode is 10ns */
} DW_IIC_SPKLEN, *DW_IIC_SPKLEN_PTR;

/** IIC Clock SCL High and Low Count Configurations for Different Speed */
typedef struct dw_iic_scl_cnt {
	uint32_t ss_scl_hcnt;   /*!< value for IC_SS_SCL_HCNT */
	uint32_t ss_scl_lcnt;   /*!< value for IC_SS_SCL_LCNT */
	uint32_t fs_scl_hcnt;   /*!< value for IC_FS_SCL_HCNT */
	uint32_t fs_scl_lcnt;   /*!< value for IC_FS_SCL_LCNT */
	uint32_t hs_scl_hcnt;   /*!< value for IC_HS_SCL_HCNT */
	uint32_t hs_scl_lcnt;   /*!< value for IC_HS_SCL_LCNT */
} DW_IIC_SCL_CNT, *DW_IIC_SCL_CNT_PTR;

#define DW_IIC_GINT_DISABLED            (0)             /*!< designware interrupt disabled for control iic irq/fiq */
#define DW_IIC_GINT_ENABLE              (1 << 0)        /*!< designware interrupt enabled for control iic irq/fiq */
#define DW_IIC_TXINT_ENABLE             (1 << 1)        /*!< designware interrupt enabled for control transmit process */
#define DW_IIC_RXINT_ENABLE             (1 << 2)        /*!< designware interrupt enabled for control transmit process */

typedef struct dw_iic_buffer {
	DEV_BUFFER *buf;
	uint32_t ofs;
	uint32_t len;
} DW_IIC_BUFFER, *DW_IIC_BUFFER_PTR;

/**
 * @brief	DesignWare IIC control structure definition
 * @details	implement of dev_iic_info::iic_ctrl
 */
typedef struct dw_iic_ctrl {
	DW_IIC_REG *dw_iic_regs;                /*!< iic device registers */
	/* Variables which should be set during object implementation */
	uint32_t ic_clkhz;                      /*!< IC clock in HZ */
	uint32_t ic_caploading;                 /*!< I2C Bus cap loading pf */
	uint32_t support_modes;                 /*!< supported iic modes */
	uint32_t tx_fifo_len;                   /*!< transmit fifo length */
	uint32_t rx_fifo_len;                   /*!< receive fifo length */
	uint32_t iic_master_code;               /*!< value for IC_HS_MADDR */
	uint32_t retry_cnt;                     /*!< retry count for TX or RX */
	uint32_t intno;                         /*!< iic interrupt vector number */
	INT_HANDLER_T dw_iic_int_handler;       /*!< iic interrupt handler */
	DW_IIC_SPKLEN iic_spklen;               /*!< iic spike suppression length settings */
	DW_IIC_SCL_CNT iic_scl_cnt;             /*!< iic scl count settings */
	/* Variables which always change during iic operation */
	uint32_t int_status;                    /*!< iic interrupt status */
	uint32_t iic_tx_over;                   /*!< iic tx overflow count */
	uint32_t iic_rx_over;                   /*!< iic rx overflow count */
	DW_IIC_BUFFER dw_iic_rxbuf;             /*!< iic read buffer for receive data */
} DW_IIC_CTRL, *DW_IIC_CTRL_PTR;

/*!< One possible value for \ref dw_iic_ctrl::retry_cnt */
#define DW_IIC_MAX_RETRY_COUNT                  (100000)

#define DW_IIC_FS_SPKLEN_NS                     (50)
#define DW_IIC_HS_SPKLEN_NS                     (10)

#define MIN_DW_IIC_SS_SCL_LCNT(spklen)          ((spklen) + 7)
#define MIN_DW_IIC_FS_SCL_LCNT(spklen)          ((spklen) + 7)

#define MIN_DW_IIC_SS_SCL_HCNT(spklen)          ((spklen) + 5)
#define MIN_DW_IIC_FS_SCL_HCNT(spklen)          ((spklen) + 5)

#define MIN_DW_IIC_HS_SCL_LCNT(spklen)          ((spklen) + 7)
#define MIN_DW_IIC_HS_SCL_HCNT(spklen)          ((spklen) + 5)

#define MIN_DW_IIC_SS_HIGH_TIME_NS              (4000)
#define MIN_DW_IIC_SS_LOW_TIME_NS               (4700)

#define MIN_DW_IIC_FS_HIGH_TIME_NS              (600)
#define MIN_DW_IIC_FS_LOW_TIME_NS               (1300)

#define MIN_DW_IIC_HS_100PF_HIGH_TIME_NS        (60)
#define MIN_DW_IIC_HS_100PF_LOW_TIME_NS         (160)

#define MIN_DW_IIC_HS_400PF_HIGH_TIME_NS        (120)
#define MIN_DW_IIC_HS_400PF_LOW_TIME_NS         (320)

#ifdef __cplusplus
extern "C" {
#endif

extern int32_t dw_iic_open(DEV_IIC *iic_obj, uint32_t mode, uint32_t param);
extern int32_t dw_iic_close(DEV_IIC *iic_obj);
extern int32_t dw_iic_control(DEV_IIC *iic_obj, uint32_t ctrl_cmd, void *param);
extern int32_t dw_iic_write(DEV_IIC *iic_obj, const void *data, uint32_t len);
extern int32_t dw_iic_read(DEV_IIC *iic_obj, void *data, uint32_t len);
extern void dw_iic_isr(DEV_IIC *iic_obj, void *ptr);

#ifdef __cplusplus
}
#endif

#endif /* _DW_IIC_H_ */
